#ifndef __MY_MESSAGE_H__
#define __MY_MESSAGE_H__

#include "defines.h"
#include "object.h"
#include "thread.h"
#include "utils.h"
#include "blockingpriorityqueue.h"

#include "mlog.h"

// ref android message/handler
class Message {
private:
	using obj_sp = std::shared_ptr<Object>;
	using msg_sp = std::shared_ptr<Message>;

public:
	uint32_t what_ = 0;
	uint32_t arg1_ = 0, arg2_ = 0;
	obj_sp data_;
	int64_t when_ = 0;
	Runnable callback_ = nullptr;

public:
	Message() { }
	virtual ~Message() {
		// std::cout << "destroy message: what=" << what_ << std::endl;
	}

	static msg_sp obtain() {
		return std::make_shared<Message>();
	}

	static msg_sp getPostMessage(Runnable r) {
		auto m = obtain();
		m->callback_ = r;
		return m;
	}

public:
	bool operator < (const Message& m) const {
		// MLOG_DEBUG("operator 1");
		return when_ > m.when_;
	}

	friend bool operator < (const msg_sp& left, const msg_sp& right) {
		// MLOG_DEBUG("operator 2");
		return left->when_ > right->when_;
	}

	void dump() const {
		MLOG_DEBUG("what={}, when={}", what_, when_);
	}
};


class MessageHandler : public Thread {
private:
	using msg_sp = std::shared_ptr<Message>;

private:
	BlockingPriorityQueue<Message> queue_;

protected:
	void dispatchMessage(msg_sp msg) {
		if (msg->callback_) {
			msg->callback_();
		} else {
			handleMessage(msg);
		}
	}

public:
	void run() override {
		while (is_start()) {
			auto msg = queue_.take(false);
			auto when = Utils::whenMs(Utils::now());
			if (when >= msg->when_) {
				dispatchMessage(msg);
				queue_.pop();
			}
		}
	}

public:
	void sendMessage(msg_sp msg) {
		sendMessageDelay(msg, 0);
	}

	void sendMessageDelay(msg_sp msg, int delayMs) {
		msg->when_ = Utils::whenMs(Utils::now()) + tmax(delayMs, 0);
		queue_.put(msg);
	}

	void post(Runnable r) {
		postDelayed(r, 0);
	}

	void postDelayed(Runnable r, int delayMs) {
		sendMessageDelay(Message::getPostMessage(r), delayMs);
	}

public:
	virtual void handleMessage(msg_sp msg) = 0;
};

#endif // __MY_MESSAGE_H__
